package de.upb.aquarium.water.bubbles;

import java.util.LinkedList;
import java.util.List;

import de.upb.aquarium.World;
import de.upb.aquarium.api.utility.VectorFloat;

public class PointBubbleSource extends BubbleSource {

	private double spawnRatio;
	private double maxSpeed;
	private double maxDeviation;
	private double lastUpdateTime;
	private double timeToNextSpawn;
	
	private VectorFloat toLeft;
	private VectorFloat toFront;
	
	public PointBubbleSource(
			VectorFloat position,
			VectorFloat upDirection,
			double spawnRatio, double maxSpeed, double maxDeviation) {
		super(position, upDirection);
		this.spawnRatio		= spawnRatio;
		this.maxSpeed		= maxSpeed;
		this.maxDeviation	= maxDeviation;
		this.lastUpdateTime	= World.getInstance().getGlobalTime();
		this.timeToNextSpawn = 0.0;
		
		VectorFloat e1 = new VectorFloat(new float[] {1.0f, 0.0f, 0.0f});
		VectorFloat e2 = new VectorFloat(new float[] {0.0f, 1.0f, 0.0f});
		
		e1 = e1.CrossProduct(getUpDirection());
		e2 = e2.CrossProduct(getUpDirection());
		
		toLeft = (e1.norm() > e2.norm()) ? e1 : e2;
		toFront = getUpDirection().CrossProduct(toLeft);
	}

	@Override
	public List<WaterBubble> generate() {
		
		List<WaterBubble> result = new LinkedList<WaterBubble>();
		
		while (World.getInstance().getElapsedTime(lastUpdateTime) > timeToNextSpawn)
		{
			lastUpdateTime += timeToNextSpawn;
			
			timeToNextSpawn = -Math.log(Math.random())/spawnRatio;
			
			double deviationUp		= maxDeviation*Math.random();
			double deviationLeft	= maxDeviation*(2*Math.random() - 1.0);
			double deviationFront	= maxDeviation*(2*Math.random() - 1.0);
			
			VectorFloat initialMovement = getUpDirection().mul(deviationUp);
			initialMovement = initialMovement.add(toLeft.mul(deviationLeft));
			initialMovement = initialMovement.add(toFront.mul(deviationFront));
			
			result.add(new WaterBubble(maxSpeed,
					   getPosition(),
					   getUpDirection(),
					   initialMovement));
		}
		
		return result;
	}

}
